#include "user.h"
#include "rsa.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h> /* For O_* constants */
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <assert.h>


#include "userSqliteOp.h"

#include "chartSqliteOp.h"

#include "log.h"
#include "serv_socket_handle.h"

ALL_DATA *g_all_data = NULL;

extern const char *SQL_COMMAND_CREAT_USER_TABLE;
extern const char *SQL_COMMAND_CREAT_CHART_TABLE;

extern pthread_mutex_t sqlite3OpenMutex;


/** 
 * generatSession
 * @Descript:
 * @Author	:hezuoqiang
 * @DateTime:2019�?10�?31�?T19:19:24+0800
 * @param	id	:
 * @RETURN VALUE 
 * @    On success, zero is returned.  On error, negative number is returned
 */
int generatSession(u_int64_t id)
{
	char sessionBuf[NAME_PASSWD_SESSION_LEN];
	create_rand_printable_string(sessionBuf,NAME_PASSWD_SESSION_LEN);
	return updateSession(id,sessionBuf);
}


/**
 * @brief  初�?�化服务器的工作�??径，创建或映射用户数�??文件到全局指针g_all_data
 * !@note  用户数据保存�??./serv.data文件�?? 
 * @retval 成功返回0,失败返回一�??负数
 */
int server_file_path_init()
{
    int fd = 0;
    int first_flag = 1; //SHM_SERVER_NAME,需要初始化user_number=0
    // struct stat sb;

    /* 1. create shm, set its size, map it, close descriptor */
    fd = open(SHM_SERVER_NAME, O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
    if (fd == -1 && errno == EEXIST)
    {
        fd = open(SHM_SERVER_NAME, O_RDWR | O_CREAT, FILE_MODE);
        add_log("second shm_open() %s\n", SHM_SERVER_NAME);
        first_flag = 0;
    }
    else
    {
        add_log("first shm_open() %s\n", SHM_SERVER_NAME);
    }
    if (fd == -1)
    {
        perror("shm_open()");
        return -1;
    }
    if (ftruncate(fd, sizeof(ALL_DATA)) == -1)
    {
        perror("ftruncate()");
        close(fd);
        return -3;
    }
    // if (fstat(fd, &sb) == -1) /* To obtain file size */
    //     return -1;

    // if (sizeof(ALL_DATA) >= sb.st_size)
    // {
    //     fprintf(stderr, "offset is past end of file\n");
    //     return -1;
    // }
    g_all_data = mmap(NULL, sizeof(ALL_DATA), PROT_READ | PROT_WRITE, MAP_SHARED, fd,0 & ~(sysconf(_SC_PAGE_SIZE) - 1));
    if (g_all_data == MAP_FAILED || g_all_data == NULL)
    {
        perror("mmap()1");
        close(fd);
        return -2;
    }
    // if (ftruncate(fd, sizeof(ALL_DATA)) == -1)
    // {
    //     perror("ftruncate()");
    //     close(fd);
    //     return -3;
    // }
    close(fd);
    if (first_flag)
    {
        g_all_data->user_number = 0;
        pthread_mutex_init(&g_all_data->mutex, NULL);
    }

    /* 2.g_all_data->user_data_addr */
    user_data_mmap();
    return 0;
}
/**
 * @brief  用户数据映射，将用户数据文件映射�?? g_all_data->user_data_addr
 * @note   注册用户的数�??保存�??./data/server.data
 * @retval 成功返回0，失败返回一�??负数
 */
int user_data_mmap()
{
    pthread_mutex_lock(&g_all_data->mutex);
    int fd = open(SERVER_DATA_FILE, O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
    if (fd == -1 && errno == EEXIST)
    {
        fd = open(SERVER_DATA_FILE, O_RDWR | O_CREAT, FILE_MODE);
    }
    if (fd == -1)
    {
        perror("shm_open()2");
        return -1;
    }
    
    if (ftruncate(fd, sizeof(USER_DATA) * g_all_data->user_number) == -1)
    {
        perror("ftruncate()2");
        close(fd);
        pthread_mutex_unlock(&g_all_data->mutex);
        return -3;
    }
    g_all_data->user_data_addr = NULL;
    g_all_data->user_data_addr = mmap(NULL, sizeof(USER_DATA) * (g_all_data->user_number + 1), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (g_all_data->user_data_addr == MAP_FAILED || g_all_data->user_data_addr == NULL)
    {
        pthread_mutex_unlock(&g_all_data->mutex);
        perror("mmap()2");
        close(fd);
        return -2;
    }
    close(fd);
    pthread_mutex_unlock(&g_all_data->mutex);
    return 0;
}

/** 
 * create_rand_printable_string
 * @Descript:生成一串随机字�?(a~z,A~Z),最后一�?字�?��?�置结束�?0
 * @Author	:hezuoqiang
 * @DateTime:2019�?10�?31�?T19:55:44+0800
 * @param	string	:
 * @param	num	:
 * @RETURN VALUE 
 * @    On success, zero is returned.  On error, negative number is returned
 */
int create_rand_printable_string(char *string, int num)
{
	assert(num > 0);
    assert(string != NULL);
	int fd_rand = open("/dev/urandom", O_RDONLY);
    if (fd_rand == -1)
    {
        perror("open /dev/urandom");
        return -1;
    }
	int i = 0,c=0;
    while (i < num)
    {
        i += read(fd_rand, &c, 1);
		c = c %26;
		string[i -1] = (char)c+'a';
    }
	string[i -1] = 0;
    if (fd_rand > 2)
    {
        close(fd_rand);
        fd_rand = -1;
    }
	return 0;
}
/**
 * @brief  生成一�??随机的字符串
 * !@note  通过读取/dev/urandom文件的方式生成随机数
 * @param  num: 字�?�串的个�??
 * @param  *string: 保存字�?�串的地址
 * @retval 成功返回0
 */
int create_rand_string(int num, char *string)
{
    assert(num > 0);
    assert(string != NULL);

    int fd_rand = open("/dev/urandom", O_RDONLY);
    if (fd_rand == -1)
    {
        perror("open /dev/urandom");
        return -1;
    }
    int i = 0;
    while (i < num)
    {
        i += read(fd_rand, string + i, num - i);
    }
    if (fd_rand > 2)
    {
        close(fd_rand);
        fd_rand = -1;
    }
    return 0;
}
/**
 * @brief  初�?�化数据�?
 * @note   检�?user表是否存�?,不存在则创建
 * @param  *dbName: 
 * @retval 
 */
int initDatabase()
{
    sqlite3 *db = NULL;
    int ret;
	/* 1.初�?�化用户信息数据�? */
    ret = my_sqlite3_open(DB_NAME, &db);
    UTIL_ASSERT(!ret);

	/* 2.创建用户�? */
    if (isTableExit(db, USER_TABLE_NAME) != TABLE_EXITED)
    {
        ret = createTable(db, USER_TABLE_NAME, SQL_COMMAND_CREAT_USER_TABLE);
        UTIL_ASSERT(ret == SUCCESS);
    }
	
	/* 3.创建聊天�? */
	if (isTableExit(db, CHART_TABLE_NAME) != TABLE_EXITED)
    {
        ret = createTable(db, CHART_TABLE_NAME, SQL_COMMAND_CREAT_CHART_TABLE);
        UTIL_ASSERT(ret == SUCCESS);
    }
	my_sqlite3_close(db);
    return SUCCESS;
}

